/**
 ** Copyright (c) 2010, GE Healthcare
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 ** following conditions are met:
 ** 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 **    following disclaimer.
 ** 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
 **    disclaimer in the documentation and/or other materials provided with the distribution.
 ** 3. Neither the name of the GE Healthcare nor the names of its contributors may be used to endorse or promote products
 **    derived from this software without specific prior written permission.
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 ** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * This software was created by its contributors for NHINDirect.org for the sole purpose of demonstrating the
 * viability of using Integrating the Healthcare Enterprise (IHE) in accordance with the proposed
 * IHE NHIN Direct Specfication.
 *
 * References:
 * http://nhindirect.org/
 * http://nhindirect.org/NHIN+Direct+Abstract+Model
 * http://nhindirect.org/IHE+NHIN+Direct+Specification
 *
 * Contributors:
 * mailto:/matt.potter@ge.com
 */

package org.nhindirect.rest;

import org.apache.log4j.Logger;
import org.nhindirect.XDMArchiver;
import org.nhindirect.XDRDocumentSource;
import org.openhealthtools.ihe.xds.source.SubmitTransactionData;
import org.restlet.Context;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.ResourceException;
import org.restlet.resource.Variant;

import java.io.File;
import java.io.FileOutputStream;
import java.net.URI;
import java.text.MessageFormat;


/**
 * Demonstrates the use of OpenHealthTools (OHT) to transform and send via XDR the contents of
 * an XDM payload received via a bare bones REST endpoint.  Rest uses the lightweight
 * Restlet 1.1 library http://www.restlet.org/downloads/
 */
public class XDMResource extends Resource {


    private static final Logger LOGGER = Logger.getLogger(XDMResource.class);

    static final String KEY_XDR_SOURCE_ID = "xdrSourceOid";
    static final String KEY_XDR_SOURCE_AGENT_NAME = "xdrSourceAgentName";
    static final String KEY_XDR_DOCUMENT_RECIPIENT_ENDPOINT_URI = "xdrEndpointUri";
    static final String HTTP_EXT_HEADER_PREFIX = "X-";

    public XDMResource(Context context, Request request, Response response) {
        super(context, request, response);

        setModifiable(true);
        setReadable(false);

        getVariants().add(new Variant(MediaType.APPLICATION_OCTET_STREAM));
        getVariants().add(new Variant(MediaType.APPLICATION_ZIP));
    }

    @Override
    public void acceptRepresentation(Representation entity) throws ResourceException {

        File file = null;
        XDRDocumentSource xdrDocumentSource = null;
        SubmitTransactionData[] transactions = null;

        try {
            // stream bytes to temp file
            file = File.createTempFile("xdm_", ".zip", new File("."));
            FileOutputStream fos = new FileOutputStream(file);
            entity.write(fos);
            fos.close();

            Form requestHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers");
            String xdrEndpointUriString = requestHeaders.getFirstValue(HTTP_EXT_HEADER_PREFIX + KEY_XDR_DOCUMENT_RECIPIENT_ENDPOINT_URI);
            String xdrSourceOid = requestHeaders.getFirstValue(HTTP_EXT_HEADER_PREFIX + KEY_XDR_SOURCE_ID);
            String xdrSourceAgentName = requestHeaders.getFirstValue(HTTP_EXT_HEADER_PREFIX + KEY_XDR_SOURCE_AGENT_NAME);
            URI xdrEndpointUri = null;

            if (xdrEndpointUriString != null) {
                try {
                    xdrEndpointUri = new URI(xdrEndpointUriString);
                    LOGGER.info("REQUEST: " + HTTP_EXT_HEADER_PREFIX + KEY_XDR_DOCUMENT_RECIPIENT_ENDPOINT_URI + " = " + xdrEndpointUriString);
                } catch (Exception e) {
                    LOGGER.error("Bad URI in REST header " + HTTP_EXT_HEADER_PREFIX + KEY_XDR_DOCUMENT_RECIPIENT_ENDPOINT_URI + " = " + xdrEndpointUriString);
                    throw new RuntimeException(e);
                }
            } else {
                xdrEndpointUri = (URI) getContext().getAttributes().get(KEY_XDR_DOCUMENT_RECIPIENT_ENDPOINT_URI);
            }
            if (xdrSourceOid != null) {
                LOGGER.info("REQUEST: " + HTTP_EXT_HEADER_PREFIX + KEY_XDR_SOURCE_ID + " = " + xdrSourceOid);
            } else {
                xdrSourceOid = (String) getContext().getAttributes().get(KEY_XDR_SOURCE_ID);
            }
            if (xdrSourceAgentName != null) {
                LOGGER.info("REQUEST: " + HTTP_EXT_HEADER_PREFIX + KEY_XDR_SOURCE_AGENT_NAME + " = " + xdrSourceAgentName);
            } else {
                xdrSourceAgentName = (String) getContext().getAttributes().get(KEY_XDR_SOURCE_AGENT_NAME);
            }

            // setup the 'XDR client' playing role of XDR document source
            xdrDocumentSource = new XDRDocumentSource(xdrSourceOid, xdrSourceAgentName, xdrEndpointUri);

            // load XDM to XD[SR] transactions (XDM archive may contain mulitple transactions)
            transactions = XDMArchiver.loadXDMArchive(file);

        } catch (Exception e) {
            LOGGER.error(MessageFormat.format("FAILURE: converting XDM archive {0}",
                    file.getAbsolutePath()));
            throw new ResourceException(e);
        }

        try {

            // submit each submission set in XDM archive as a separate XDR transaction
            for (SubmitTransactionData txnData : transactions) {
                xdrDocumentSource.submit(txnData);
            }

            LOGGER.info(MessageFormat.format("SUCCESS: converted XDM archive {0} to {1} XDR transactions(s) to {2}",
                    file.getAbsolutePath(), transactions.length,
                    ((URI) getContext().getAttributes().get(KEY_XDR_DOCUMENT_RECIPIENT_ENDPOINT_URI)).toASCIIString()));

            // delete temp file
            //file.delete();

        } catch (Exception e) {
            LOGGER.error(MessageFormat.format("FAILURE: submitting XDM archive {0} in {1} XDR transactions(s) to {2}",
                    file.getAbsolutePath(), transactions.length,
                    ((URI) getContext().getAttributes().get(KEY_XDR_DOCUMENT_RECIPIENT_ENDPOINT_URI)).toASCIIString()));
            throw new ResourceException(e);
        }
    }
}
